﻿using Awsc.DataAcquisitionSys.Core.Common;
using Awsc.DataAcquisitionSys.Core.Messages;
using Awsc.DataAcquisitionSys.Core.Model.Config;
using Awsc.DataAcquisitionSys.Core.Models.Config;
using MediatR;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System.Net.Sockets;
using System.Text;

namespace Awsc.DataAcquisitionSys.Core.Services.ConfigManagement
{
    public interface IDeviceConfigService
    {
        DeviceConfig GetDeviceConfig();
        Task<bool> AddCollectorAsync(CollectorConfig config);
        Task<bool> UpdateCollectorAsync(string collectorName, CollectorConfig collectorConfig);
        Task<bool> RemoveCollectorAsync(string collectorName);
        Task<bool> AddRegisterAsync(string collectorName, RegisterConfig config);
        Task<bool> UpdateRegisterAsync(string collectorName, string registerName, RegisterConfig registerConfig);
        Task<bool> RemoveRegisterAsync(string collectorName, string registerName);
        Task<bool> AddCoilAsync(string collectorName, CoilConfig config);
        Task<bool> UpdateCoilAsync(string collectorName,string coilName, CoilConfig coilConfig);
        Task<bool> RemoveCoilAsync(string collectorName, string coilName);
        Task<bool> SyncConfigToDisplayControlCabinetAsync();
        Task<bool> AddCameraAsync(CameraConfig cameraConfig);
        Task<bool> UpdateCameraAsync(string cameraName, CameraConfig cameraConfig);
        Task<bool> RemoveCameraAsync(string cameraName);



    }
    public class DeviceConfigService : IDeviceConfigService
    {
        private readonly IOptionsMonitor<DeviceConfig> optionsMonitor;
        private readonly IMediator mediator;
        private readonly ApplicationParameters applicationParameters;

        public DeviceConfigService(IOptionsMonitor<DeviceConfig> optionsMonitor, IOptions<ApplicationParameters> options,IMediator mediator)
        {
            this.optionsMonitor = optionsMonitor;
            this.mediator = mediator;
            this.applicationParameters = options.Value;
        }
        public DeviceConfig GetDeviceConfig()
        {
            return optionsMonitor.CurrentValue;
        }
        public async Task<bool> AddCollectorAsync(CollectorConfig config)
        {
            var deviceConfig = optionsMonitor.CurrentValue;
            if (deviceConfig.Collectors.Any(c => c.Name == config.Name))
            {
                throw new Exception($"已经存在名为\"{config.Name}\"的采集器。");
            }
            deviceConfig.Collectors.Add(config);
            await SyncConfigToFileAsync(deviceConfig);
            return true;

        }

        public async Task<bool> UpdateCollectorAsync(string collectorName, CollectorConfig collectorConfig)
        {
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            deviceConfig.Collectors.Remove(collector);
            deviceConfig.Collectors.Add(collectorConfig);
            await SyncConfigToFileAsync(deviceConfig);
            return true;
        }
        public async Task<bool> RemoveCollectorAsync(string collectorName)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            deviceConfig.Collectors.Remove(collector);
            await SyncConfigToFileAsync(deviceConfig);
            return true;

        }


        public async Task<bool> AddRegisterAsync(string collectorName, RegisterConfig config)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNull(config);
            ArgumentAssert.NotNullOrEmpty(config.Name);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            RegisterConfig register = null;

            if (config.RegisterType == RegisterType.AO)
            {
                register = collector.OutputRegisters.FirstOrDefault(r => r.Name == config.Name);
                if (register != null)
                {
                    throw new Exception($"采集器{collectorName}上已存在名为\"{config.Name}\"的输出寄存器。");
                }
                collector.OutputRegisters.Add(config);
            }
            else
            {
                register = collector.InputRegisters.FirstOrDefault(r => r.Name == config.Name);
                if (register != null)
                {
                    throw new Exception($"采集器{collectorName}上已存在名为\"{config.Name}\"的输入寄存器。");
                }
                collector.InputRegisters.Add(config);
            }

            await SyncConfigToFileAsync(deviceConfig);
            await mediator.Publish(new AddSensorMessage(config));
            return true;
        }
        public async Task<bool> UpdateRegisterAsync(string collectorName, string registerName, RegisterConfig config)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNull(config);
            ArgumentAssert.NotNullOrEmpty(config.Name);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            RegisterConfig register = null;

            if (config.RegisterType == RegisterType.AO)
            {
                register = collector.OutputRegisters.FirstOrDefault(r => r.Name == registerName);
                if (register == null)
                {
                    throw new Exception($"采集器{collectorName}上不存在名为\"{registerName}\"的输出寄存器。");
                }
                collector.OutputRegisters.Remove(register);
                collector.OutputRegisters.Add(config);
            }
            else
            {
                register = collector.InputRegisters.FirstOrDefault(r => r.Name == registerName);
                if (register == null)
                {
                    throw new Exception($"采集器{collectorName}上不存在名为\"{registerName}\"的输入寄存器。");
                }
                collector.InputRegisters.Remove(register);
                collector.InputRegisters.Add(config);
            }

            await SyncConfigToFileAsync(deviceConfig);
            return true;
        }
        public async Task<bool> RemoveRegisterAsync(string collectorName, string registerName)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNullOrEmpty(registerName);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            var config = collector.InputRegisters.FirstOrDefault(r => r.Name == registerName);
            if(config==null)
            {
                config = collector.OutputRegisters.FirstOrDefault(r => r.Name == registerName);
                if(config==null)
                {
                    throw new Exception($"采集器\"{collectorName}\"上不存在名为\"{registerName}\"的寄存器。");
                }
            }
            collector.InputRegisters.RemoveAll(r => r.Name == registerName);
            collector.OutputRegisters.RemoveAll(r => r.Name == registerName);
            await SyncConfigToFileAsync(deviceConfig);
            await mediator.Publish(new RemoveSensorMessage(config));
            return true;
        }
        public async Task<bool> AddCoilAsync(string collectorName, CoilConfig config)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNull(config);
            ArgumentAssert.NotNullOrEmpty(config.Name);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            var coilType = config.CoilType;
            if (coilType == CoilType.DO)
            {
                var coil = collector.OutputCoils.FirstOrDefault(c => c.Name == config.Name);
                if (coil != null)
                {
                    throw new Exception($"采集器{collectorName}上已存在名为\"{config.Name}\"的输出线圈。");
                }

                collector.OutputCoils.Add(config);
            }
            else
            {
                var coil = collector.InputCoils.FirstOrDefault(c => c.Name == config.Name);
                if (coil != null)
                {
                    throw new Exception($"采集器{collectorName}上已存在名为\"{config.Name}\"的输入线圈。");
                }
                collector.InputCoils.Add(config);
            }

            await SyncConfigToFileAsync(deviceConfig);
            await mediator.Publish(new AddSensorMessage(config));
            return true;
        }

        public async Task<bool> UpdateCoilAsync(string collectorName, string coilName, CoilConfig config)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNull(config);
            ArgumentAssert.NotNullOrEmpty(config.Name);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            var coilType = config.CoilType;
            CoilConfig coil = null;
            if (coilType == CoilType.DO)
            {
                coil = collector.OutputCoils.FirstOrDefault(c => c.Name == coilName);
                if (coil == null)
                {
                    throw new Exception($"采集器{collectorName}上不存在名为\"{coilName}\"的输出线圈。");
                }

                collector.OutputCoils.Remove(coil);
                collector.OutputCoils.Add(config);

            }
            else
            {
                coil = collector.InputCoils.FirstOrDefault(c => c.Name == coilName);
                if (coil == null)
                {
                    throw new Exception($"采集器{collectorName}上不存在名为\"{config.Name}\"的输出线圈。");
                }

                collector.InputCoils.Remove(coil);
                collector.InputCoils.Add(config);
            }


            await SyncConfigToFileAsync(deviceConfig);
            return true;

        }
        public async Task<bool> RemoveCoilAsync(string collectorName, string coilName)
        {
            ArgumentAssert.NotNullOrEmpty(collectorName);
            ArgumentAssert.NotNullOrEmpty(coilName);
            var deviceConfig = optionsMonitor.CurrentValue;
            var collector = deviceConfig.Collectors.FirstOrDefault(c => c.Name == collectorName);
            if (collector == null)
            {
                throw new Exception($"不存在名为\"{collectorName}\"的采集器。");
            }
            var config = collector.InputCoils.FirstOrDefault(r => r.Name == coilName);
            if(config==null)
            {
                config = collector.OutputCoils.FirstOrDefault(r => r.Name == coilName);
                if(config==null)
                {
                    throw new Exception($"采集器\"{collectorName}\"上不存在名为\"{coilName}\"的线圈。");
                }
            }
            collector.InputCoils.RemoveAll(r => r.Name == coilName);
            collector.OutputCoils.RemoveAll(r => r.Name == coilName);
            await SyncConfigToFileAsync(deviceConfig);
            await mediator.Publish(new RemoveSensorMessage(config));
            return true;

        }
        public async Task<bool> AddCameraAsync(CameraConfig cameraConfig)
        {
            ArgumentAssert.NotNull(cameraConfig);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.IP);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.Name);
            ArgumentAssert.GreaterThanZero(cameraConfig.Port);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.Password);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.UserName);
            var deviceConfig = optionsMonitor.CurrentValue;

            var camera = deviceConfig.Cameras.FirstOrDefault(c => c.Name == cameraConfig.Name);
            if (camera != null)
            {
                throw new Exception($"已存在名为\"{camera}\"的摄像头。");
            }
            deviceConfig.Cameras.Add(cameraConfig);
            await SyncConfigToFileAsync(deviceConfig);
            return true;
        }

        public async Task<bool> UpdateCameraAsync(string cameraName, CameraConfig cameraConfig)
        {
            ArgumentAssert.NotNullOrEmpty(cameraName);
            ArgumentAssert.NotNull(cameraConfig);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.IP);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.Name);
            ArgumentAssert.GreaterThanZero(cameraConfig.Port);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.Password);
            ArgumentAssert.NotNullOrEmpty(cameraConfig.UserName);
            var deviceConfig = optionsMonitor.CurrentValue;

            var camera = deviceConfig.Cameras.FirstOrDefault(c => c.Name == cameraName);
            if (camera == null)
            {
                throw new Exception($"不存在名为\"{cameraName}\"的摄像头。");
            }
            deviceConfig.Cameras.Remove(camera);
            deviceConfig.Cameras.Add(cameraConfig);
            await SyncConfigToFileAsync(deviceConfig);
            return true;
        }

        public async Task<bool> RemoveCameraAsync(string cameraName)
        {
            ArgumentAssert.NotNullOrEmpty(cameraName);
            var deviceConfig = optionsMonitor.CurrentValue;
            var camera = deviceConfig.Cameras.FirstOrDefault(c => c.Name == cameraName);
            if (camera == null)
            {
                throw new Exception($"不存在名为\"{cameraName}\"的摄像头。");
            }
            deviceConfig.Cameras.Remove(camera);
            await SyncConfigToFileAsync(deviceConfig);
            return true;
        }

        public async Task<bool> SyncConfigToDisplayControlCabinetAsync()
        {
            bool ret = false;
            string ip = applicationParameters.RemoteIP;
            int port = applicationParameters.RemotePort;
            TcpClient c = new TcpClient();
            try
            {
                c.ReceiveTimeout = 5000;
                c.SendTimeout = 5000;
                IAsyncResult res = c.BeginConnect(ip, port, null, null);
                var success = res.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));

                if (success)
                {
                    try
                    {
                        string content = this.optionsMonitor.CurrentValue.DeviceType.ToString();
                        byte[] cbs = Encoding.UTF8.GetBytes(content);
                        byte[] bs = new byte[cbs.Length + 8];
                        bs[0] = 1;
                        bs[1] = 2;
                        bs[2] = 3;
                        bs[3] = 3;
                        bs[bs.Length - 1] = 1;
                        bs[bs.Length - 2] = 2;
                        bs[bs.Length - 3] = 3;
                        bs[bs.Length - 4] = 5;
                        Array.Copy(cbs, 0, bs, 4, cbs.Length);
                        c.Client.Send(bs);

                        int l = c.Client.Receive(bs);
                        if (l > 0)
                        {
                            if (Encoding.UTF8.GetString(bs, 0, l) == "RCVOK")
                            {
                                ret = true;
                            }
                        }
                        else
                        {

                        }
                    }
                    catch (System.Exception ex)
                    {

                    }
                    c.Close();
                }
                else
                {
                    c.EndConnect(res);
                }

            }
            catch (System.Exception ex)
            {

            }
            return ret;
        }
        private async Task SyncConfigToFileAsync(DeviceConfig deviceConfig)
        {
            var configPath = Path.Combine(Directory.GetCurrentDirectory(), "dataCollectionConfig.json");
            var json = JsonConvert.SerializeObject(deviceConfig, new JsonSerializerSettings()
            {
                Formatting = Formatting.Indented
            });
            await File.WriteAllTextAsync(configPath, json);
        }


    }
}
